package com.example.design;

import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * 策略模式（Strategy）：它定义了算法家族，分别封装起来，让它们之间可以相互替换，此模式让算法的变化，不会影响到使用算法的客户
 * 策略模式就是用来封装算法的，但在实践中，我们发现可以用它来封装几乎任何类型的规则，只要在分析过程中听到需要在不同时间应用不同的业务规则，就可以考虑使用策略模式处理这种变化的可能性
 * 策略模式并不能解决需求频繁变更的问题，任何需求变更都是需要成本的，使用策略模式只是让需求变更的成本更小了；
 * 可以使用反射来优化
 * @author xiaohf
 * @createTime 2021/8/26 20:52
 **/
public class Strategy {

    public static void main(String[] args) {
        double money = 1028.23;

        //简单工厂实现收银策略
        CashStrategy cashStrategy = CashFactory.createCashSuper("满300返100");
        double cashFactoryResult = cashStrategy.acceptCash(money);
        System.out.println(String.format("简单工厂：实付%s元,应收%s元",Double.toString(money),Double.toString(cashFactoryResult)));

        //策略模式实现收银策略
        String strategy = "正常收费";
        CashContext cashContext;
        switch (strategy) {
            case "正常收费":
                cashContext = new CashContext(new CashNormalStrategy());

                break;
            case "满300返100":
                cashContext = new CashContext(new CashReturnStrategy(300, 100));
                break;
            case "打8折":
                cashContext = new CashContext(new CashRebateStrategy(0.8));
                break;
            default:
                cashContext = new CashContext(new CashNormalStrategy());
        }

        double cashContextResult = cashContext.getResult(money);
        System.out.println(String.format("策略模式：实付%s元,应收%s元",Double.toString(money),Double.toString(cashContextResult)));

        //策略模式与简单工厂结合
        CashContextFactory cashContextFactory = new CashContextFactory("打8折");
        double cashContextFactoryResult = cashContextFactory.getResult(money);
        System.out.println(String.format("策略模式+简单工厂：实付%s元,应收%s元",Double.toString(money),Double.toString(cashContextFactoryResult)));

    }

}
abstract class CashStrategy {
    public abstract double acceptCash(double money);
}

/**
 * 正常收费策略
 * @author xiaohf
 * @createTime 2021/8/26 21:08
 **/
class CashNormalStrategy extends CashStrategy {

    @Override
    public double acceptCash(double money) {
        return money;
    }
}

/**
 * 打折收费策略
 * @author xiaohf
 * @createTime 2021/8/26 21:07
 **/
class CashRebateStrategy extends CashStrategy {

    private double moneyRebate;

    public CashRebateStrategy(double moneyRebate) {
        this.moneyRebate = moneyRebate;
    }

    @Override
    public double acceptCash(double money) {
        DecimalFormat decimalFormat = new DecimalFormat("#.##");
        return Double.parseDouble(decimalFormat.format(money * moneyRebate));
    }

}

/**
 * 打折收费策略
 * @author xiaohf
 * @createTime 2021/8/26 21:07
 **/
class CashReturnStrategy extends CashStrategy {

    private double moneyCondition;
    private double moneyReturn;

    public CashReturnStrategy(double moneyCondition, double moneyReturn) {
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }

    @Override
    public double acceptCash(double money) {
        double result = money;
        if (money > moneyCondition) {
            result = money - Math.floor(money / moneyCondition) * moneyReturn;
        }
        return result;
    }
}

class CashFactory {
    public static CashStrategy createCashSuper(String strategy) {
        CashStrategy cashStrategy;
        switch (strategy) {
            case "正常收费":
                cashStrategy = new CashNormalStrategy();
                break;
            case "满300返100":
                cashStrategy = new CashReturnStrategy(300, 100);
                break;
            case "打8折":
                cashStrategy = new CashRebateStrategy(0.8);
                break;
            default:
                cashStrategy = new CashNormalStrategy();
        }
        return cashStrategy;
    }
}

/**
 * 收银上下文
 * @author xiaohf
 * @createTime 2021/8/26 21:43
 **/
class CashContext {
    //声明一个收银策略
    private CashStrategy cashStrategy;

    public CashContext(CashStrategy cashStrategy) {
        this.cashStrategy = cashStrategy;
    }

    public double getResult(double money) {
        return cashStrategy.acceptCash(money);
    }
}

/**
 * 收银上下文(策略+简单工厂的结合使用)
 * @author xiaohf
 * @createTime 2021/8/26 21:43
 **/
class CashContextFactory {
    //声明一个收银策略
    private CashStrategy cashStrategy;

    public CashContextFactory(String strategy) {
        switch (strategy) {
            case "正常收费":
                cashStrategy =new CashNormalStrategy();
                break;
            case "满300返100":
                cashStrategy = new CashReturnStrategy(300, 100);
                break;
            case "打8折":
                cashStrategy = new CashRebateStrategy(0.8);
                break;
            default:
                cashStrategy = new CashNormalStrategy();
        }
    }

    public double getResult(double money) {
        return cashStrategy.acceptCash(money);
    }
}

